#coding:utf-8

import ast
import re
import sys
reload(sys)
sys.setdefaultencoding('utf8')

from common.exception import ParamsError
from dbutil import MysqldbHelper
db = MysqldbHelper()
variable_regexp = r"\$([\w_]+)"
function_regexp = re.compile(r"^\$\{([\w_]+)\(([\$\w_ =,]*)\)\}$")


def get_contain_variables(content):
    """ extract all variable names from content, which is in format $variable
    @param (str) content
    @return (list) variable name list
    """
    return re.findall(variable_regexp, content)

def parse_variables(content, variable_mapping):
    """ replace all variables of string content with mapping value.
    @param (str) content
    @return (str) parsed content
    """
    variable_name_list = get_contain_variables(content)
    for variable_name in variable_name_list:
        variable_value = variable_mapping.get(variable_name)
        #if not in variable_mapping then search in db
        if variable_value is None:
            variable_value = parse_variables_db(variable_name)
            print variable_value
            if variable_value is None:
                raise ParamsError(
                    "%s is not defined in bind variables or DB variables!" % variable_name)


        if "${}".format(variable_name) == content:
            # content is a variable
            content = variable_value
        else:
            # content contains one or many variables
            content = content.replace(
                "${}".format(variable_name),
                str(variable_value)
            )

    return content


def is_functon(content):
    """ check if content is a function, which is in format ${func()}
    @param (str) content
    @return (bool) True or False
    """
    matched = function_regexp.match(content)
    return True if matched else False

def parse_string_value(str_value):
    """ parse string to number if possible
    """
    try:
        return ast.literal_eval(str_value)
    except ValueError:
        return str_value
    except SyntaxError:
        return str_value

def parse_function(content):
    """ parse function name and args from string content.
    @param (str) content
    @return (dict) function name and args
    """
    function_meta = {
        "args": [],
        "kwargs": {}
    }
    matched = function_regexp.match(content)
    function_meta["func_name"] = matched.group(1)

    args_str = matched.group(2).replace(" ", "")
    if args_str == "":
        return function_meta

    args_list = args_str.split(',')
    for arg in args_list:
        if '=' in arg:
            key, value = arg.split('=')
            function_meta["kwargs"][key] = parse_string_value(value)
        else:
            function_meta["args"].append(parse_string_value(arg))

    return function_meta

def parse_content_with_bindings(content, variables_binds, functions_binds):
    """ evaluate content recursively, each variable in content will be
        evaluated with bind variables and functions.
    """

    if isinstance(content, (list, tuple)):
        return [
            parse_content_with_bindings(item, variables_binds, functions_binds)
            for item in content
        ]

    if isinstance(content, dict):
        evaluated_data = {}
        for key, value in content.items():
            evaluated_data[key] = parse_content_with_bindings(
                value, variables_binds, functions_binds)

        return evaluated_data

    if isinstance(content, (int, float)):
        return content

    content = "" if content is None else content.strip()

    if is_functon(content):
        fuction_meta = parse_function(content)
        func_name = fuction_meta['func_name']

        func = functions_binds.get(func_name)
        if func is None:
            raise ParamsError(
                "%s is not defined in bind functions!" % func_name)

        args = fuction_meta.get('args', [])
        kwargs = fuction_meta.get('kwargs', {})
        args = parse_content_with_bindings(args, variables_binds, functions_binds)
        kwargs = parse_content_with_bindings(kwargs, variables_binds, functions_binds)
        return func(*args, **kwargs)

    elif get_contain_variables(content):
        parsed_data = parse_variables(content, variables_binds)
        return parsed_data

    else:
        return content

def getValue(testDbName,testDbField,bizDbName,bizDbFiled):
    while True:
        sql = "select %s from %s where status = 1 ORDER BY id ASC limit 1" % (testDbField, testDbName)
        results = db.select(sql)
        # print results
        if len(results) == 0:
            return None

        for row in results:
            # print "查询到的数据：%s" % row
            sql = "update %s set status = 0, ts = now(), useage = 'interface auto test' WHERE %s = '%s'" %(testDbName, testDbField, row[0])
            db.update(sql)
            bizSql = "select * from %s where %s = '%s'" % (bizDbName,bizDbFiled,row[0])
            countBus = db.selectBus(bizSql)

            if len(countBus) == 0:
                break
            else:
                return row[0]

def parse_variables_db(var_value):
    if var_value.upper() == "DEPARTMENTID":
        # testDbName testDbField为测试数据库中查询的表和字段
        testDbName = "t_avl_deptID"
        testDbField = "dept_id"
        # bizDbName bizDbFiled为业务数据库中查询的表和字段
        bizDbName = "sys_department"
        bizDbFiled = "id"

    return getValue(testDbName,testDbField,bizDbName,bizDbFiled)




if __name__ == '__main__':
    variable_value = "departmentID"
    value = parse_variables_db(variable_value)
    print value

